package msg

import (
	"gitee.com/shuohe/xutils"
	"gitee.com/shuohe/xutils/xbuf"
	"gitee.com/shuohe/xutils/xerror"
	"io"
	"strconv"
	"gitee.com/shuohe/xutils/xcrypto/base58"
)

type FieldInfo struct {
	Id           int
	Name         string
	BitMask      uint32
	Type         int
	LenValidator ILengthValidator
	FmtValidator IFormatValidator
}

const (
	FieldType_String = iota
	FieldType_Int
	FieldType_Bytes
)

const (
	MsgType_GenkeyRequest   = "1010"
	MsgType_GenkeyResponse  = "1011"
	MsgType_GetkeyRequest   = "1020"
	MsgType_GetkeyResponse  = "1021"
	MsgType_EncryptRequest  = "1030"
	MsgType_EncryptResponse = "1031"
	MsgType_SignRequest     = "1040"
	MsgType_SignResponse    = "1041"
	MsgType_VerifyRequest   = "1050"
	MsgType_VerifyResponse  = "1051"
)

const (
	RetCode_Ok          = "00"
	RetCode_EMsgType    = "01"
	RetCode_EMsgFormat  = "02"
	RetCode_EOptions    = "03"
	RetCode_EKeyAlgo    = "04"
	RetCode_EKeyIndex1  = "05"
	RetCode_EKeyIndex2  = "06"
	RetCode_ESecretKey1 = "07"
	RetCode_ESecretKey2 = "08"
	RetCode_EPublicKey  = "09"
	RetCode_EPrivateKey = "0A"
	RetCode_EMeterial   = "0B"
	RetCode_ESignature  = "0C"
	RetCode_EKeyType    = "0D"
)

var (
	MsgType  = &FieldInfo{0, "MsgType", uint32(1), FieldType_String, &FixedLengthValidator{4}, &DigitValidator{}}
	RetCode  = &FieldInfo{1, "RetCode", uint32(1) << 1, FieldType_String, &FixedLengthValidator{2}, &AlphaDigitValidator{}}
	Options  = &FieldInfo{2, "Options", uint32(1) << 2, FieldType_String, &FixedLengthValidator{2}, &DigitValidator{}}
	KeyAlgo  = &FieldInfo{3, "KeyAlgo", uint32(1) << 3, FieldType_String, &VarLengthValidator{3,16}, &PrintableValidator{}}
	VerifyOk = &FieldInfo{4, "VerifyOk", uint32(1) << 4, FieldType_String, &FixedLengthValidator{1}, &DigitValidator{}}

	KeyIndex1 = &FieldInfo{5, "KeyIndex1", uint32(1) << 5, FieldType_Int, nil, &IntRangeValidator{1, 9999}}
	KeyIndex2 = &FieldInfo{6, "KeyIndex2", uint32(1) << 6, FieldType_Int, nil, &IntRangeValidator{1, 9999}}

	SecretKey1 = &FieldInfo{7, "SecretKey1", uint32(1) << 7, FieldType_Bytes, &VarLengthValidator{16,64}, nil}
	SecretKey2 = &FieldInfo{8, "SecretKey2", uint32(1) << 8, FieldType_Bytes, &VarLengthValidator{16,64}, nil}
	PublicKey  = &FieldInfo{9, "PublicKey", uint32(1) << 9, FieldType_Bytes, &VarLengthValidator{32, 256}, nil}
	PrivateKey = &FieldInfo{10, "PrivateKey", uint32(1) << 10, FieldType_Bytes, &VarLengthValidator{32, 256}, nil}
	Meterial   = &FieldInfo{11, "Meterial", uint32(1) << 11, FieldType_Bytes, &VarLengthValidator{0, 4096}, nil}
	Signature  = &FieldInfo{12, "Signature", uint32(1) << 12, FieldType_Bytes, &VarLengthValidator{0, 256}, nil}

	Fields = [...]*FieldInfo{
		MsgType,
		RetCode,
		Options,
		KeyAlgo,
		VerifyOk,
		KeyIndex1,
		KeyIndex2,
		SecretKey1,
		SecretKey2,
		PublicKey,
		PrivateKey,
		Meterial,
		Signature,
	}
)

type Bitmap32Message struct {
	bitmap uint32
	fields [32]interface{}
}

func (this *Bitmap32Message) Exists(field *FieldInfo) bool {
	return this.fields[field.Id] != nil
}

func (this *Bitmap32Message) GetString(field *FieldInfo) string {
	if this.fields[field.Id] == nil {
		return ""
	}
	return xutils.Bytes2String(this.fields[field.Id].([]byte))
}

func (this *Bitmap32Message) GetInt(field *FieldInfo) int64 {
	if this.fields[field.Id] == nil {
		return 0
	}
	return this.fields[field.Id].(int64)
}

func (this *Bitmap32Message) GetBytes(field *FieldInfo) []byte {
	if this.fields[field.Id] == nil {
		return []byte{}
	}
	return this.fields[field.Id].([]byte)
}

func (this *Bitmap32Message) SetString(field *FieldInfo, value string) {
	this.fields[field.Id] = xutils.String2Bytes(value)
}

func (this *Bitmap32Message) SetInt(field *FieldInfo, value int64) {
	this.fields[field.Id] = value
}

func (this *Bitmap32Message) SetBytes(field *FieldInfo, value []byte) {
	this.fields[field.Id] = value
}

func (this *Bitmap32Message) MarshalX(xb *xbuf.Buffer) {
	// 记下当前写指针位置，并跳过四个字节
	wi1 := xb.WriteIndex
	xb.EnsureWrite(4)
	xb.WriteIndex += 4

	// 循环一次，写入存在的字段，同时计算位图
	this.bitmap = 0
	for i, f := range Fields {
		v := this.fields[i]
		if v == nil {
			continue
		}
		if f.Type == FieldType_Int {
			xb.WriteVarint(v.(int64))
		} else {
			xb.WriteVarbytes(v.([]byte))
		}

		this.bitmap |= f.BitMask
	}

	// 写指针跳回开始位置，写入四字节的位图字段，然后写指针跳回当前
	wi2 := xb.WriteIndex
	xb.WriteIndex = wi1
	xb.WriteUint32(this.bitmap)
	xb.WriteIndex = wi2
}

func (this *Bitmap32Message) Marshal() []byte {
	xb := xbuf.New(1024)
	this.MarshalX(xb)

	return xb.Bytes()
}

func (this *Bitmap32Message) UnmarshalX(xb *xbuf.Buffer) error {
	bmp, err := xb.ReadUint32()
	if err != nil {
		return xerror.Wrap(err, "Failed to read field bitmap.")
	}
	this.bitmap = bmp

	for i, f := range Fields {
		if this.bitmap & f.BitMask == 0 {
			continue
		}

		var v interface{}

		if f.Type == FieldType_Int {
			v, err = xb.ReadVarint()
		} else {
			v, err = xb.ReadVarbytes()
		}
		if err != nil {
			return xerror.Wrapf(err, "Failed to read field '%s'.", f.Name)
		}

		this.fields[i] = v
	}

	return nil
}

func (this *Bitmap32Message) Unmarshal(msg []byte) error {
	xb := xbuf.WrapForRead(msg)
	return this.UnmarshalX(xb)
}

func (this *Bitmap32Message) ValidateFields() error {
	for i, f := range Fields {
		v := this.fields[i]
		if v == nil {
			continue
		}
		if f.LenValidator != nil && !f.LenValidator.ValidateLength(v) {
			return xerror.Newf("Length error of field '%s'.", f.Name)
		}
		if f.FmtValidator != nil && !f.FmtValidator.ValidateFormat(v) {
			return xerror.Newf("Format error of field '%s'.", f.Name)
		}
	}

	return nil
}

func (this *Bitmap32Message) Dump(w io.Writer, indent string) {
	xb := xbuf.New(1024)
	for i, f := range Fields {
		if this.fields[i] == nil {
			continue
		}
		
		xb.WriteString(indent)
		xb.WriteString(f.Name)
		xb.WriteString(": ")
		
		if f.Type == FieldType_String {
			v, ok := this.fields[i].([]byte)
			if !ok {
				xb.WriteString("<incorrect value type>")
			} else {
				xb.WriteBytes(v)
			}
		} else if f.Type == FieldType_Bytes {
			v, ok := this.fields[i].([]byte)
			if !ok {
				xb.WriteString("<incorrect value type>")
			} else {
				xb.WriteString("base58://")
				xb.WriteString(base58.Encode(v))
			}
		} else {
			v, ok := this.fields[i].(int64)
			if !ok {
				xb.WriteString("<incorrect value type>")
			} else {
				xb.WriteString(strconv.Itoa(int(v)))
			}
		}
		xb.WriteString("\n")
	}

	w.Write(xb.Bytes())
}

func Bitmap32Message_Unmarshal(data []byte) (*Bitmap32Message, error) {
	msg := &Bitmap32Message{}
	return msg, msg.Unmarshal(data)
}